package br.ufpe.cin.bf.codegenerator.actions;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.validation.model.EvaluationMode;
import org.eclipse.emf.validation.service.IBatchValidator;
import org.eclipse.emf.validation.service.ModelValidationService;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.xpand2.XpandExecutionContextImpl;
import org.eclipse.xpand2.XpandFacade;
import org.eclipse.xpand2.output.Outlet;
import org.eclipse.xpand2.output.OutputImpl;
import org.eclipse.xtend.expression.Variable;
import org.eclipse.xtend.typesystem.emf.EmfRegistryMetaModel;

import br.ufpe.cin.bf.BenchmarkingFramework;
import br.ufpe.cin.bf.BfPackage;
import br.ufpe.cin.bf.diagram.part.BfInitDiagramFileAction;
import br.ufpe.cin.bf.persistence.ModelLoad;

public class GenerateCode extends BfInitDiagramFileAction {

	private IWorkbenchPart targetPart;
	private File modelInstance;
	private String fileLocation;
	
	
	@Override
	public void run(IAction action) {
		
		modelInstance = new File(fileLocation);
		
		//Validate the model object
		BenchmarkingFramework bf = ModelLoad.load(fileLocation);
		IBatchValidator validator = (IBatchValidator) ModelValidationService
				.getInstance().newValidator(EvaluationMode.BATCH);
		validator.setIncludeLiveConstraints(true);
		IStatus status = validator.validate(bf);
		
		if(!status.isOK()){
			MessageDialog.openInformation(targetPart.getSite().getShell(), "Error", "Please fix the errors in the diagram to be able to generate the code." +
					"Run validate under Edit->Validate or save your diagram file to show them in the diagram UI.");
		} else{
			IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
			IResource resource = root.findMember(new Path(modelInstance.getParent()));
			String containerName = resource.getProject().getLocation().toPortableString();
			
			OutputImpl output = new OutputImpl();
			Outlet outlet = new Outlet(containerName);
			outlet.setOverwrite(true);
			output.addOutlet(outlet);
			
			Map<String,Variable> globalVarsMap = new HashMap<String,Variable>();

			XpandExecutionContextImpl execCtx = new XpandExecutionContextImpl(
					output, null, globalVarsMap, null, null);
			EmfRegistryMetaModel metamodel = new EmfRegistryMetaModel() {
				@Override
				protected EPackage[] allPackages() {
					return new EPackage[] { BfPackage.eINSTANCE,
							EcorePackage.eINSTANCE };
				}
			};
			execCtx.registerMetaModel(metamodel);
			
			XpandFacade facade = XpandFacade.create(execCtx);
			String templatePath = "template::BfTemplate::main";
			facade.evaluate(templatePath, bf );
			templatePath = "template::rootTemplate::main";
			facade.evaluate(templatePath, bf );
			templatePath = "template::cssTemplate::main";
			facade.evaluate(templatePath, bf );
			templatePath = "template::jsTemplate::main";
			facade.evaluate(templatePath, bf );
			templatePath = "template::utilTemplate::main";
			facade.evaluate(templatePath, bf );
			
			try {
				resource.refreshLocal(IResource.DEPTH_INFINITE, null);
			} catch (CoreException e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public void selectionChanged(IAction action, ISelection selection) {
		fileLocation = null;
		action.setEnabled(false);
		if (selection instanceof IStructuredSelection == false
				|| selection.isEmpty()) {
			return;
		}
		IFile file = (IFile) ((IStructuredSelection) selection)
				.getFirstElement();
		fileLocation = file.getFullPath().toString();
		action.setEnabled(true);
	}

	@Override
	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
		this.targetPart = targetPart;
	}

}
